home *** CD-ROM | disk | FTP | other *** search
/ The Atari Compendium / The Atari Compendium (Toad Computers) (1994).iso / files / umich / network / ka9q / ka9q_src.arc / IP.C < prev    next >
C/C++ Source or Header  |  1988-11-29  |  10KB  |  387 lines

  1. /* Upper half of IP, consisting of send/receive primitives, including
  2.  * fragment reassembly, for higher level protocols.
  3.  * Not needed when running as a standalone gateway.
  4.  */
  5. #define    TLB        30    /* Reassembly limit time */
  6. #include "global.h"
  7. #include "mbuf.h"
  8. #include "timer.h"
  9. #include "internet.h"
  10. #include "iface.h"
  11. #include "ip.h"
  12. #include "icmp.h"
  13.  
  14. int ip_recv();    /* Should be void, but C complains */
  15.  
  16. char ip_ttl = MAXTTL;    /* Default time-to-live for IP datagrams */
  17.  
  18. struct reasm *reasmq;
  19.  
  20. #define    INSERT    0
  21. #define    APPEND    1
  22. #define    PREPEND    2
  23.  
  24. /* Send an IP datagram. Modeled after the example interface on p 32 of
  25.  * RFC 791
  26.  */
  27. void
  28. ip_send(source,dest,protocol,tos,ttl,bp,length,id,df)
  29. int32 source;        /* source address */
  30. int32 dest;        /* Destination address */
  31. char protocol;        /* Protocol */
  32. char tos;        /* Type of service */
  33. char ttl;        /* Time-to-live */
  34. struct mbuf *bp;    /* Data portion of datagram */
  35. int16 length;        /* Optional length of data portion */
  36. int16 id;        /* Optional identification */
  37. char df;        /* Don't-fragment flag */
  38. {
  39.     struct mbuf *htonip();
  40.     struct ip ip;        /* Pointer to IP header */
  41.     static int16 id_cntr;    /* Datagram serial number */
  42.     void ip_route();    /* Datagram router */
  43.  
  44.     if(length == 0 && bp != NULLBUF)
  45.         length = len_mbuf(bp);
  46.     if(id == 0)
  47.         id = id_cntr++;        
  48.     if(ttl == 0)
  49.         ttl = ip_ttl;
  50.  
  51.     /* Fill in IP header */
  52.     ip.tos = tos;
  53.     ip.length = IPLEN + length;
  54.     ip.id = id;
  55.     if(df)
  56.         ip.fl_offs = DF;
  57.     else
  58.         ip.fl_offs = 0;
  59.     ip.ttl = ttl;
  60.     ip.protocol = protocol;
  61.     ip.source = source;
  62.     ip.dest = dest;
  63.     ip.optlen = 0;
  64.     bp = htonip(&ip,bp);
  65.     ip_route(bp,0);        /* Toss it to the router */
  66. }
  67.  
  68. /* Reassemble incoming IP fragments and dispatch completed datagrams
  69.  * to the proper transport module
  70.  */
  71. int    /* Should really be void */
  72. ip_recv(bp,rxbroadcast)
  73. struct mbuf *bp;
  74. char rxbroadcast;
  75. {
  76.     struct ip ip;        /* Extracted copy of header */
  77.     struct mbuf *fraghandle();
  78.     void (*recv)();    /* Function to call with completed datagram */
  79.     void tcp_input(),udp_input(),icmp_input();
  80.  
  81.     ntohip(&ip,&bp);
  82.  
  83.     /* Initial check for protocols we can't handle */
  84.     switch(ip.protocol & 0xff){
  85.     case TCP_PTCL:
  86.         recv = tcp_input;
  87.         break;
  88.     case UDP_PTCL:
  89.         recv = udp_input;
  90.         break;
  91.     case ICMP_PTCL:
  92.         recv = icmp_input;
  93.         break;
  94.     default:
  95.         /* Send an ICMP Protocol Unknown response... */
  96.         ip_stats.badproto++;
  97.         /* ...unless it's a broadcast */
  98.         if(!rxbroadcast){
  99.             icmp_output(&ip,bp,DEST_UNREACH,PROT_UNREACH,(union icmp_args *)0);
  100.         }
  101.         free_p(bp);
  102.         return;
  103.     }
  104.     /* If we have a complete packet, call the next layer
  105.      * to handle the result. Note that fraghandle passes back
  106.      * a length field that does NOT include the IP header
  107.      */
  108.     if((bp = fraghandle(&ip,bp)) != NULLBUF)
  109.         (*recv)(bp,ip.protocol,ip.source,ip.dest,ip.tos,
  110.             ip.length - (IPLEN + ip.optlen),rxbroadcast);
  111. }
  112. /* Process IP datagram fragments
  113.  * If datagram is complete, return it with ip->length containing the data
  114.  * length (MINUS header); otherwise return NULLBUF
  115.  */
  116. static
  117. struct mbuf *
  118. fraghandle(ip,bp)
  119. struct ip *ip;        /* IP header, host byte order */
  120. struct mbuf *bp;    /* The fragment itself */
  121. {
  122.     void ip_timeout(),freefrag(),free_reasm();
  123.     struct reasm *lookup_reasm(),*creat_reasm();
  124.     register struct reasm *rp; /* Pointer to reassembly descriptor */
  125.     struct frag *lastfrag,*nextfrag,*tfp,*newfrag();
  126.     struct mbuf *tbp;
  127.     int16 i;
  128.     int16 offset;        /* Index of first byte in fragment */
  129.     int16 last;        /* Index of first byte beyond fragment */
  130.     char mf;        /* 1 if not last fragment, 0 otherwise */
  131.  
  132.     offset = (ip->fl_offs & F_OFFSET) << 3;    /* Convert to bytes */
  133.     last = offset + ip->length - (IPLEN + ip->optlen);
  134.     mf = (ip->fl_offs & MF) ? 1 : 0;
  135.  
  136.     rp = lookup_reasm(ip);
  137.     if(offset == 0 && !mf){
  138.         /* Complete datagram received. Discard any earlier fragments */
  139.         if(rp != NULLREASM)
  140.             free_reasm(rp);
  141.  
  142.         return bp;
  143.     }
  144.     if(rp == NULLREASM){
  145.         /* First fragment; create new reassembly descriptor */
  146.         if((rp = creat_reasm(ip)) == NULLREASM){
  147.             /* No space for descriptor, drop fragment */
  148.             free_p(bp);
  149.             return NULLBUF;
  150.         }
  151.     }
  152.     /* Keep restarting timer as long as we keep getting fragments */
  153.     stop_timer(&rp->timer);
  154.     start_timer(&rp->timer);
  155.  
  156.     /* If this is the last fragment, we now know how long the
  157.      * entire datagram is; record it
  158.      */
  159.     if(!mf)
  160.         rp->length = last;
  161.  
  162.     /* Set nextfrag to the first fragment which begins after us,
  163.      * and lastfrag to the last fragment which begins before us
  164.      */
  165.     lastfrag = NULLFRAG;
  166.     for(nextfrag = rp->fraglist;nextfrag != NULLFRAG;nextfrag = nextfrag->next){
  167.         if(nextfrag->offset > offset)
  168.             break;
  169.         lastfrag = nextfrag;
  170.     }
  171.     /* Check for overlap with preceeding fragment */
  172.     if(lastfrag != NULLFRAG  && offset < lastfrag->last){
  173.         /* Strip overlap from new fragment */
  174.         i = lastfrag->last - offset;
  175.         pullup(&bp,NULLCHAR,i);
  176.         if(bp == NULLBUF)
  177.             return NULLBUF;    /* Nothing left */
  178.         offset += i;
  179.     }
  180.     /* Look for overlap with succeeding segments */
  181.     for(; nextfrag != NULLFRAG; nextfrag = tfp){
  182.         tfp = nextfrag->next;    /* save in case we delete fp */
  183.  
  184.         if(nextfrag->offset >= last)
  185.             break;    /* Past our end */
  186.         /* Trim the front of this entry; if nothing is
  187.          * left, remove it.
  188.          */
  189.         i = last - nextfrag->offset;
  190.         pullup(&nextfrag->buf,NULLCHAR,i);
  191.         if(nextfrag->buf == NULLBUF){
  192.             /* superseded; delete from list */
  193.             if(nextfrag->prev != NULLFRAG)
  194.                 nextfrag->prev->next = nextfrag->next;
  195.             else
  196.                 rp->fraglist = nextfrag->next;
  197.             if(tfp->next != NULLFRAG)
  198.                 nextfrag->next->prev = nextfrag->prev;
  199.             freefrag(nextfrag);
  200.         } else
  201.             nextfrag->offset = last;
  202.     }
  203.     /* Lastfrag now points, as before, to the fragment before us;
  204.      * nextfrag points at the next fragment. Check to see if we can
  205.      * join to either or both fragments.
  206.      */
  207.     i = INSERT;
  208.     if(lastfrag != NULLFRAG && lastfrag->last == offset)
  209.         i |= APPEND;
  210.     if(nextfrag != NULLFRAG && nextfrag->offset == last)
  211.         i |= PREPEND;
  212.     switch(i){
  213.     case INSERT:    /* Insert new desc between lastfrag and nextfrag */
  214.         tfp = newfrag(offset,last,bp);
  215.         tfp->prev = lastfrag;
  216.         tfp->next = nextfrag;
  217.         if(lastfrag != NULLFRAG)
  218.             lastfrag->next = tfp;    /* Middle of list */
  219.         else
  220.             rp->fraglist = tfp;    /* First on list */
  221.         if(nextfrag != NULLFRAG)
  222.             nextfrag->prev = tfp;
  223.         break;
  224.     case APPEND:    /* Append to lastfrag */
  225.         append(&lastfrag->buf,bp);
  226.         lastfrag->last = last;    /* Extend forward */
  227.         break;
  228.     case PREPEND:    /* Prepend to nextfrag */
  229.         tbp = nextfrag->buf;
  230.         nextfrag->buf = bp;
  231.         append(&nextfrag->buf,tbp);
  232.         nextfrag->offset = offset;    /* Extend backward */
  233.         break;
  234.     case (APPEND|PREPEND):
  235.         /* Consolidate by appending this fragment and nextfrag
  236.          * to lastfrag and removing the nextfrag descriptor
  237.          */
  238.         append(&lastfrag->buf,bp);
  239.         append(&lastfrag->buf,nextfrag->buf);
  240.         nextfrag->buf = NULLBUF;
  241.         lastfrag->last = nextfrag->last;
  242.  
  243.         /* Finally unlink and delete the now unneeded nextfrag */
  244.         lastfrag->next = nextfrag->next;
  245.         if(nextfrag->next != NULLFRAG)
  246.             nextfrag->next->prev = lastfrag;
  247.         freefrag(nextfrag);
  248.         break;
  249.     }
  250.     if(rp->fraglist->offset == 0 && rp->fraglist->next == NULLFRAG 
  251.         && rp->length != 0){
  252.         /* We've gotten a complete datagram, so extract it from the
  253.          * reassembly buffer and pass it on.
  254.          */
  255.         bp = rp->fraglist->buf;
  256.         rp->fraglist->buf = NULLBUF;
  257.         /* Tell IP the entire length */
  258.         ip->length = rp->length + (IPLEN + ip->optlen);
  259.         free_reasm(rp);
  260.         return bp;
  261.     } else
  262.         return NULLBUF;
  263. }
  264. static struct reasm *
  265. lookup_reasm(ip)
  266. struct ip *ip;
  267. {
  268.     register struct reasm *rp;
  269.  
  270.     for(rp = reasmq;rp != NULLREASM;rp = rp->next){
  271.         if(ip->source == rp->source && ip->dest == rp->dest
  272.          && ip->protocol == rp->protocol && ip->id == rp->id)
  273.             return rp;
  274.     }
  275.     return NULLREASM;
  276. }
  277. #ifdef    FOO
  278. static
  279. int16
  280. hash_reasm(source,dest,protocol,id)
  281. int32 source;
  282. int32 dest,
  283. char protocol;
  284. int16 id;
  285. {
  286.     register int16 hval;
  287.  
  288.     hval = loword(source);
  289.     hval ^= hiword(source);
  290.     hval ^= loword(dest);
  291.     hval ^= hiword(dest);
  292.     hval ^= protocol &